package gui;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPopupMenu;

import threads.ThreadCrearEnemigo;
import threads.ThreadMana;
import threads.ThreadPelea;
import threads.ThreadMoverEnemigo;
import threads.ThreadAtaqueTorres;
import unidad.Unidad;
import unidad.Enemigo;
import juego.Logica;
import gui.Nivel;

import unidad.*;

public class Supervisor 
{
	protected ThreadMoverEnemigo tme;
	protected ThreadCrearEnemigo tce;
	protected ThreadAtaqueTorres tp;
	protected ThreadMana tm;
	protected ThreadPelea tPelea;
	protected Logica logica;
	protected Nivel gui;
	protected Map<JLabel,Unidad> mapeo;
	
	public Supervisor(Nivel n)
	{
		tme = new ThreadMoverEnemigo(this,n,20);
		tce = new ThreadCrearEnemigo(this);
		tp = new ThreadAtaqueTorres(this);
		tm = new ThreadMana(this);
		tPelea = new ThreadPelea(this);
		logica = new Logica(this);
		mapeo = new HashMap<JLabel,Unidad>();
		gui = n;
	}
	
	public int puntuacion()
	{
		return logica.obtPuntuacion();
	}
	
	public float mana()
	{
		return logica.obtMana();
	}
	
	public void modificarPuntuacion(int m)
	{
		logica.modificarPuntuacion(m);
		gui.modificarPunt(logica.obtPuntuacion());
	}
	
	public void modificarMana(float m)
	{
		logica.modificarMana(m);
		gui.modificarMana(logica.obtMana());
	}
	
	protected void nuevoJuego()
	{
		logica = new Logica(this);
	}
	
	protected void iniciarThreads()
	{
		tme.start();
		tce.start();
		tp.start();
		tPelea.start();
		tm.start();
	}
	
	protected void apagarThreads()
	{
		tme.terminar();
		tce.terminar();
		tp.terminar();
		tPelea.terminar();
		tm.terminar();
	}
	
	protected void crearNuevosThreads()
	{
		tme = new ThreadMoverEnemigo(this,gui,20);
		tce = new ThreadCrearEnemigo(this);
		tp = new ThreadAtaqueTorres(this);
		tPelea = new ThreadPelea(this);
		tm = new ThreadMana(this);
	}
	
	public void crearUnidad(final JLabel labelUnidad, int TUnidad, int fila, int columna)
	{
		final Unidad nuevaUnidad;
		if(TUnidad > 0)
		{
			nuevaUnidad = logica.crearTorre(TUnidad, fila, columna);
			if(nuevaUnidad != null)
			{
				mapeo.put(labelUnidad,nuevaUnidad);
				JPopupMenu popupMenu = new JPopupMenu();
				addPopup(labelUnidad, popupMenu);
				JButton arma1 = new JButton("Machine-Gun");
				arma1.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent e) 
					{	
						if(logica.tieneMana(30))
						{
							gui.cambiarArma(labelUnidad,"Machine-Gun");
							Arma nuevaArma = new Machine();
							logica.ponerLuzEnTorre(nuevaUnidad, nuevaArma);
							logica.modificarMana(-30);
							gui.modificarMana(logica.obtMana());
						}
				}
			});
				JButton arma2 = new JButton("Doble Gun");
				arma2.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent e) 
					{	
						
						if(logica.tieneMana(50))
						{
							gui.cambiarArma(labelUnidad,"DobleMachine");
							Arma nuevaArma = new DobleMachine();
							logica.ponerLuzEnTorre(nuevaUnidad, nuevaArma);
							logica.modificarMana(-50);
							gui.modificarMana(logica.obtMana());
						}
				}
			});
				JButton arma3 = new JButton("Laser");
				arma3.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent e) 
					{	
						
						if(logica.tieneMana(100))
						{
							gui.cambiarArma(labelUnidad,"Laser");
							Arma nuevaArma = new DobleMachine();
							logica.ponerLuzEnTorre(nuevaUnidad, nuevaArma);
							logica.modificarMana(-100);
							gui.modificarMana(logica.obtMana());
						}
				}
			});
				popupMenu.add(arma1);
				popupMenu.add(arma2);
				popupMenu.add(arma3);
				gui.nuevaTorre(columna,fila,labelUnidad);
				tp.agregarTorre(labelUnidad,fila,columna);
			}
		}
		else
		{
			nuevaUnidad = logica.crearEnemigo(TUnidad, fila, TUnidad*-1);
			if(nuevaUnidad != null) //Si la logica pudo crear un enemigo
			{
				gui.crearEnemigo(fila, labelUnidad);
				mapeo.put(labelUnidad, nuevaUnidad);
				tme.nuevoEnemigo(labelUnidad);
				tp.agregarEnemigo(labelUnidad);
			}
		}
	}

	public JLabel crearDisparo(JLabel torre, int fila, int columna, int hasta)
	{
		
		JLabel disparo = gui.crearDisparo(torre.getText(),torre.getX()+torre.getWidth(), hasta,torre.getY());
		mapeo.put(disparo,mapeo.get(torre));
		return disparo;
	}

	public void quitarDisparo(JLabel dis)
	{
		mapeo.remove(dis);
		gui.quitarLabel(dis);
	}

	public int moverse(JLabel label)
	{
		Unidad aMover = mapeo.get(label);
		int mov = logica.moverse(aMover);
		return mov; 
	}
	
	public void bloquear(JLabel u)
	{
		if(u != null)
			(mapeo.get(u)).bloquear();
	}

	public void desbloquear(JLabel u)
	{
		if(u != null)
			(mapeo.get(u)).desbloquear();
	}	
	
	public int cantMov(JLabel u)
	{
		return ((Enemigo) mapeo.get(u)).getVelocidadDeMoviento();	
	}
	

	public int cantVidas()
	{
		return logica.cantidadVidas();
	}
	
	public void llegoEnemigoAlFinal(JLabel label)
	{
		gui.bajarVidas();
		noExisteMas(label);
		if(logica.perdio())
		{
			apagarThreads();
			gui.perder("Perdiste");
		}
	}
	
	//Este metodo siempre es llamado por la primer torre de cada fila
	public boolean alguienAdelante(JLabel label)
	{
		Unidad u = mapeo.get(label);
		return logica.hayUnidad(u.obtPosicionEnX()+1, u.obtPosicionEnY());
	}
	
	public void peleaTorre(JLabel enConflicto)
	{
	
		 Unidad u = mapeo.get(enConflicto);
		 tPelea.enConflictoTorre(u.obtPosicionEnY(),enConflicto);
	}
	
	public void cambiarLabelTorreAtacando(JLabel u)
	{
		gui.modificarLabelTorreAtacando(u);
	}
	
	public void cambiarLabelTorreQuieta(JLabel u)
	{
		gui.modificarLabelTorreQuietas(u);
	}
	
	public void peleaEnemigo(JLabel enConflicto)
	{
	
		// gui.modificarLabel(enConflicto);
		 Unidad u = mapeo.get(enConflicto);
		 tPelea.enConflictoEnemigo(u.obtPosicionEnY(),enConflicto);
	}
	
	public void dejoDeEstarEnConflicto(JLabel unidad)
	{
		Unidad u = mapeo.get(unidad); 
		if(u.id() > 0)
		{
			tp.agregarTorre(unidad, u.obtPosicionEnY(), u.obtPosicionEnX());
			gui.modificarLabelTorreQuietas(unidad);
		}
	}
	
	public boolean atacarEnemigo(JLabel atacante, JLabel defensora)
	{
		Unidad at = mapeo.get(atacante);
		Unidad def = mapeo.get(defensora);
		boolean fueDest = logica.atacar(at, def);
		if(fueDest)
		{
			tPelea.murio(def.obtPosicionEnY());
			dejoDeEstarEnConflicto(atacante);
			removerLabel(defensora);
			if(at.id() > 0)
			{
				logica.modificarMana(30);
				gui.modificarLabelTorreQuietas(atacante);
				gui.modificarMana(logica.obtMana());
			}
			else
				gui.modificarEnemigoCaminando(atacante);
			gui.modificarPunt(logica.obtPuntuacion());
		}
		return fueDest;
	}
	
	public void removerLabel(JLabel label)
	{
		Unidad u = mapeo.get(label);
		if(u.id() > 0)
		{
			tp.eliminarTorre(u.obtPosicionEnX(), u.obtPosicionEnY());
			gui.quitarLabel(label);
		}
		else
			tme.eliminar(label);
	}
	
	public void noExisteMas(JLabel label)
	{
		mapeo.remove(label);
	}
	
	public int obtPosY(JLabel label)
	{
		return mapeo.get(label).obtPosicionEnY();
	}
	
	public int obtPosX(JLabel label)
	{
		return mapeo.get(label).obtPosicionEnX();
	}
	
	public void volverAJugar()
	{
		crearNuevosThreads();
		nuevoJuego();
		iniciarThreads();
	}
	
	private static void addPopup(Component component, final JPopupMenu popup) {
		component.addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				if (e.isPopupTrigger()) {
					showMenu(e);
				}
			}
			public void mouseReleased(MouseEvent e) {
				if (e.isPopupTrigger()) {
					showMenu(e);
				}
			}
			private void showMenu(MouseEvent e) {
				popup.show(e.getComponent(), e.getX(), e.getY());
			}
		});
	}

	public void gano()
	{
		gui.perder("ganaste");
		apagarThreads();
	}
	
	public void agregarPrisionero(JLabel p)
	{
		gui.agregarPrisionero(p);
	}

	public void quitarPrisionero(JLabel p)
	{
		gui.quitarPrisionero(p);
	}
}
